package _Pan3D.display3D {
	import _Pan3D.base.MeshData;
	import _Pan3D.base.ObjectBone;
	import _Pan3D.base.ObjectTri;
	import _Pan3D.base.ObjectUv;
	import _Pan3D.base.ObjectWeight;
	import _Pan3D.core.Quaternion;
	import _Pan3D.display3D.analysis.AnalysisServer;
	import _Pan3D.display3D.interfaces.IDisplay3DMovie;
	import _Pan3D.load.LoadInfo;
	import _Pan3D.load.LoadManager;
	import _Pan3D.role.AnimDataManager;
	import _Pan3D.role.MeshDataManager;
	import _Pan3D.role.RoleVo;
	import _Pan3D.texture.TextureManager;
	
	import _me.Scene_data;
	
	import flash.display.Bitmap;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.Program3D;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import flash.utils.getTimer;

	// import _Pan3D.anim.Md5Analysis.Md5Analysis;
	
	/**
	 * @author MSN:liuyan3757@163.com  QQ: 421537900
	 */
	public class Display3DMovie extends Display3D implements IDisplay3DMovie
	{
		private var _meshDic:Object;
		private var _textureDic:Object;
		protected var _context:Context3D;
		protected var _animDic:Object;
		
		protected var _curentAction:String = RoleVo.STAND;
		protected var _curentFrame:int;
		
		private var _modelMatirx:Matrix3D;
		
		public var frameRate:int = 1;//播放速率
		
		public function Display3DMovie(context:Context3D)
		{
			_meshDic = new Object;
			_textureDic = new Object;
			this._context = context;
			_animDic = new Object;
			
		}
		
		public function addAnim(url:String,name:String):void{
			var obj:Object = {"name":name,"url":url};
			AnimDataManager.getInstance().addAnim(Scene_data.fileRoot+"move/"+ url + ".md5anim",onAnimLoad2,obj);
			//var loaderinfo:LoadInfo = new LoadInfo(Scene_data.fileRoot+"move/"+ url + ".md5anim",LoadInfo.XML,onAnimLoad,false,name);
			//LoadManager.getInstance().addSingleLoad(loaderinfo);
		}
		private function onAnimLoad2(ary:Array,info:Object):void{
			_animDic[info.name] = ary;
			//_curentAction = info.name;
		}
		/*private function onAnimLoad(str:String,name:String):void{
			//var t:int = getTimer();
			var ary:Array = AnalysisServer.getInstance().analysisAnim(str);
			//trace("anim解析总耗时：" + (getTimer()-t))
			//t = getTimer();
			_animDic[name] = ary;
			setFrameToMatrix(ary);
			_curentAction = name;
			//trace("anim上传耗时：" + (getTimer()-t))
		}*/
		
		public function addMesh(place:String,url:String):void{
			/*var obj:Object = {"place":place,"url":url};
			var loaderinfo:LoadInfo = new LoadInfo("../_File/textures/"+ url + ".jpg",LoadInfo.BITMAP,onTextureLoad,false,obj);
			LoadManager.getInstance().addSingleLoad(loaderinfo);*/
			var obj:Object = {"place":place,"url":url};
			TextureManager.getInstance().addTexture(Scene_data.fileRoot+"move/"+url+".jpg",addTexture,obj);
		}
		public function removeMesh(place:String):void{
			_textureDic[place] = null;
			delete _textureDic[place];
			_meshDic[place] = null;
			delete _meshDic[place];
		}
		
		private function addTexture(texture:Texture,info:Object):void{
			/*_objData.texture=texture;
			uplodToGpu();*/
			_textureDic[info.place] = texture;//bitmap.bitmapData;
			MeshDataManager.getInstance().addMesh(Scene_data.fileRoot+"move/"+ info.url + ".md5mesh",onMeshLoad2,info);
			//loadMeshData(info.place,info.url);
		}
		private function onMeshLoad2(meshData:MeshData,info:Object):void{
			meshData.texture = _textureDic[info.place];
			_meshDic[info.place] = meshData;
		}
		/*private function onTextureLoad(bitmap:Bitmap,info:Object):void{
			_textureDic[info.place] = bitmap.bitmapData;
			loadMeshData(info.place,info.url);
		}*/
		
		/*private function loadMeshData(place:String,url:String):void{
			var loaderinfo:LoadInfo = new LoadInfo(Scene_data.fileRoot+"move/"+ url + ".md5mesh",LoadInfo.XML,onMeshLoad,false,place);
			LoadManager.getInstance().addSingleLoad(loaderinfo);
		}*/
		
		/*private function onMeshLoad(str:String,place:String):void{
			//var t:int = getTimer();
			var meshData:MeshData = AnalysisServer.getInstance().analysisMesh(str);//new Md5Analysis().addMesh(str,1);
			//trace("mesh解析耗时：" + (getTimer()-t))
			//t = getTimer();
			meshData.texture = _textureDic[place];
			processForAgal(meshData);
			_meshDic[place] = meshData;
			//trace("mesh上传耗时：" + (getTimer()-t))
			this.dispatchEvent(new Event(Event.COMPLETE));
		}*/
		
		/*private function processForAgal(meshData:MeshData):void{
			var uvItem:Vector.<ObjectUv> = meshData.uvItem;
			var weightItem:Vector.<ObjectWeight> = meshData.weightItem;
			var triItem:Vector.<ObjectTri> = meshData.triItem;
			
			var uvArray:Array=new Array();
			var ary:Array = [[],[],[],[]];
			var boneWeightAry:Array = new Array;
			var bonetIDAry:Array = new Array;
			var indexAry:Array = new Array;
			
			var skipNum:int;
			var beginIndex:int;
			var allNum:int;
			
			var boneUseAry:Array = new Array;
			
			for(var i:int = 0;i<uvItem.length;i++){
				beginIndex = uvItem[i].a;
				allNum = uvItem[i].b;
				for(skipNum = 0;skipNum<4;skipNum++){
					if(skipNum<allNum){
						boneUseAry.push((weightItem[beginIndex+skipNum].boneId));
					}else{
						boneUseAry.push(0);
					}
				}
			}
			
			boneUseAry = getboneNum(boneUseAry);
			
			for(i = 0;i<uvItem.length;i++){
				beginIndex = uvItem[i].a;
				allNum = uvItem[i].b;
				for(skipNum = 0;skipNum<4;skipNum++){
					if(skipNum<allNum){
						ary[skipNum].push(weightItem[beginIndex+skipNum].x,weightItem[beginIndex+skipNum].y,weightItem[beginIndex+skipNum].z);
						bonetIDAry.push(12 + boneUseAry.indexOf((weightItem[beginIndex+skipNum].boneId))*4);
						boneWeightAry.push(weightItem[beginIndex+skipNum].w);
					}else{
						ary[skipNum].push(0,0,0);
						bonetIDAry.push(12 + boneUseAry.indexOf(0));
						boneWeightAry.push(0);
					}
				}
				uvArray.push(uvItem[i].x);
				uvArray.push(uvItem[i].y);
			}
			
			meshData.boneNewIDAry = boneUseAry;
			
			for(i=0;i<triItem.length;i++){
				indexAry.push(triItem[i].t0,triItem[i].t1,triItem[i].t2);
			}
			uplodToGpu(meshData,uvArray,ary,
						boneWeightAry,bonetIDAry,indexAry);
			//getboneNum(bonetIDAry);
		}
		private function getboneNum(ary:Array):Array{
			var numAry:Array = new Array;
			for(var i:int;i<ary.length;i++){
				if(numAry.indexOf(ary[i]) == -1){
					numAry.push(ary[i]);
				}
			}
			//trace(numAry.length);
			return numAry;
		}
		private function uplodToGpu(meshData:MeshData,uvArray:Array,ary:Array,
									boneWeightAry:Array,bonetIDAry:Array,indexAry:Array):void{
			meshData.uvBuffer = this._context.createVertexBuffer(uvArray.length/2,2);
			meshData.uvBuffer.uploadFromVector(Vector.<Number>(uvArray),0,uvArray.length/2);
			
			meshData.vertexBuffer1 = this._context.createVertexBuffer(ary[0].length/3,3);
			meshData.vertexBuffer1.uploadFromVector(Vector.<Number>(ary[0]),0,ary[0].length/3);
			
			meshData.vertexBuffer2 = this._context.createVertexBuffer(ary[1].length/3,3);
			meshData.vertexBuffer2.uploadFromVector(Vector.<Number>(ary[1]),0,ary[1].length/3);
			
			meshData.vertexBuffer3 = this._context.createVertexBuffer(ary[2].length/3,3);
			meshData.vertexBuffer3.uploadFromVector(Vector.<Number>(ary[2]),0,ary[2].length/3);
			
			meshData.vertexBuffer4 = this._context.createVertexBuffer(ary[3].length/3,3);
			meshData.vertexBuffer4.uploadFromVector(Vector.<Number>(ary[3]),0,ary[3].length/3);
			
			meshData.boneWeightBuffer = this._context.createVertexBuffer(boneWeightAry.length/4,4);
			meshData.boneWeightBuffer.uploadFromVector(Vector.<Number>(boneWeightAry),0,boneWeightAry.length/4);
			
			meshData.boneIdBuffer = this._context.createVertexBuffer(bonetIDAry.length/4,4);
			meshData.boneIdBuffer.uploadFromVector(Vector.<Number>(bonetIDAry),0,bonetIDAry.length/4);
			
			meshData.indexBuffer = this._context.createIndexBuffer(indexAry.length);
			meshData.indexBuffer.uploadFromVector(Vector.<uint>(indexAry),0,indexAry.length);
			
			//meshData.texture= this._context.createTexture(meshData.uvBitmapdata.width, meshData.uvBitmapdata.height, Context3DTextureFormat.BGRA, true);
			//meshData.texture.uploadFromBitmapData(meshData.uvBitmapdata);
			
		}*/
		
		public function update():void{
			if(!this._visible){
				return;
			}
			_context.setProgram(this.program);
			this.updateMatrix();
			_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, modelMatrix, true);
			_context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, Vector.<Number>([1, 1, 1, 0.8]));
			
			//setVc();
			for each(var meshData:MeshData in _meshDic){
				setVc(meshData);
				setVa(meshData);
			}
			
			if(_curentAction && _animDic.hasOwnProperty(_curentAction)){
				if(frames==frameRate){
					_curentFrame++;
					frames = 0;
				}else{
					frames++;
				}
				//trace("_curentFrame:" + _curentFrame)
				
				if(_curentFrame >= _animDic[_curentAction].length){
					_curentFrame = 0;
					playOver();
				}
			}
			
			resetVa();
		}
		
		public function updateForScanning(scaningProgram:Program3D):void{
			
		}
		public function updataAndScanning():void
		{
			
		}
		
		public function setMatrix(matrix:Matrix3D):void{
			this._modelMatirx = matrix;
		}
		
		public function play(action:String):void{
			if(action == _curentAction){
				return;
			}
			if(_animDic.hasOwnProperty(action)){
				_curentAction = action;
				_curentFrame = 0;
			}
		}
		
		private function setVa(meshData:MeshData):void{
			_context.setVertexBufferAt(0,meshData.vertexBuffer1, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(1,meshData.vertexBuffer2, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(2,meshData.vertexBuffer3, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(3,meshData.vertexBuffer4, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(4,meshData.uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
			_context.setVertexBufferAt(5,meshData.boneWeightBuffer, 0, Context3DVertexBufferFormat.FLOAT_4);
			_context.setVertexBufferAt(6,meshData.boneIdBuffer, 0, Context3DVertexBufferFormat.FLOAT_4);
			_context.setTextureAt(1,meshData.texture);
			_context.drawTriangles(meshData.indexBuffer, 0, -1);
		}
		
		private function resetVa():void{
			_context.setVertexBufferAt(0,null, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(1,null, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(2,null, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(3,null, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context.setVertexBufferAt(4,null, 0, Context3DVertexBufferFormat.FLOAT_2);
			_context.setVertexBufferAt(5,null, 0, Context3DVertexBufferFormat.FLOAT_4);
			_context.setVertexBufferAt(6,null, 0, Context3DVertexBufferFormat.FLOAT_4);
			_context.setTextureAt(1,null);
		}
		private var frames:int; 
		private function setVc(meshData:MeshData):void{
			if(!_curentAction){
				return;
			}
			var ary:Array = _animDic[_curentAction][_curentFrame];
			/*for(var i:int;i<ary.length;i++){
				_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 12+i*4,  ary[i].matrix, true);
			}*/
			
			var boneIDary:Array = meshData.boneNewIDAry;
			//trace("vc num:" + boneIDary.length)
			for(var i:int = 0;i<boneIDary.length;i++){
				//_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 12+i*4,  ary[i].matrix, true);
				_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 12+i*4,  ary[boneIDary[i]].matrix, true);
			}
			
		}
		
		public function playOver():void{
			
		}
		
		/*private function setFrameToMatrix(frameAry:Array):void{
			for(var j:int=0;j<frameAry.length;j++){
				var boneAry:Array = frameAry[j];
				
				var Q0:Quaternion=new Quaternion();
				var Q1:Quaternion=new Quaternion();
				var OldQ:Quaternion=new Quaternion();
				var OldM:Matrix3D=new Matrix3D();
				var newM:Matrix3D=new Matrix3D();
				var tempM:Matrix3D=new Matrix3D;
				var tempObj:ObjectBone=new ObjectBone;
				
				for(var i:int=0;i<boneAry.length;i++){
					
					var _M1:Matrix3D=new Matrix3D;
					
					var xyzfarme0:ObjectBone= boneAry[i];
					Q0=new Quaternion(xyzfarme0.qx,xyzfarme0.qy,xyzfarme0.qz);
					Q0.w= getW(Q0.x,Q0.y,Q0.z);
					var sonBone:ObjectBone=xyzfarme0;
					
					if(xyzfarme0.father==-1){
						OldQ=new Quaternion(xyzfarme0.qx,xyzfarme0.qy,xyzfarme0.qz);
						OldQ.w= getW(OldQ.x,OldQ.y,OldQ.z);
						newM=Q0.toMatrix3D();
						newM.appendTranslation(xyzfarme0.tx,xyzfarme0.ty,xyzfarme0.tz);
						//tempM=newM;
						
						xyzfarme0.qw=OldQ.w;
						xyzfarme0.matrix = newM;
						
					}else {
						var fatherBone:ObjectBone=boneAry[xyzfarme0.father];
						OldQ=new Quaternion(fatherBone.qx,fatherBone.qy,fatherBone.qz,fatherBone.qw);
						OldM=OldQ.toMatrix3D();
						OldM.appendTranslation(fatherBone.tx,fatherBone.ty,fatherBone.tz);
						var  tempV:Vector3D=OldM.transformVector(new Vector3D(sonBone.tx,sonBone.ty,sonBone.tz));
						_M1.appendTranslation(tempV.x,tempV.y,tempV.z);
						
						Q1.multiply(OldQ,Q0);
						newM=Q1.toMatrix3D();
						newM.append(_M1);
						tempM=newM;
						
						xyzfarme0.qx=Q1.x;
						xyzfarme0.qy=Q1.y;
						xyzfarme0.qz=Q1.z;
						xyzfarme0.qw=Q1.w;
						
						xyzfarme0.tx=tempV.x;
						xyzfarme0.ty=tempV.y;
						xyzfarme0.tz=tempV.z;
						xyzfarme0.tw=tempV.w;
						
						xyzfarme0.matrix = tempM;
						
					}
					//context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 12+i*4,  tempM, true);
				}
			}
		}
		
		private function getW(x:Number,y:Number,z:Number):Number{
			var t:Number = 1-(x*x + y*y + z*z);
			if(t<0){
				t=0
			}else{
				t = -Math.sqrt(t);
			}
			return t;
		}*/

		public function get curentFrame():int
		{
			return _curentFrame;
		}

		public function set curentFrame(value:int):void
		{
			_curentFrame = value;
		}
		
		override public function updatePosMatrix():void{
			var temp:Matrix3D=new Matrix3D;
			temp.prependRotation(90, Vector3D.X_AXIS);
			posMatrix.identity();
			
			posMatrix.prependTranslation(this._absoluteX, this._absoluteY, this._absoluteZ);
			posMatrix.prependScale(this._scale,this._scale,this._scale);
			posMatrix.prependRotation(_rotationY , Vector3D.Y_AXIS);
			posMatrix.prependRotation(-90, Vector3D.X_AXIS);
			
		}
		
		public function clone():Display3DMovie{
			var dis:Display3DMovie = new Display3DMovie(this._context);
			
			for(var key:String in _meshDic){
				dis._meshDic[key] = _meshDic[key];
			}
			
			for(key in _textureDic){
				dis._textureDic[key] = _textureDic[key];
			}
			
			for(key in _animDic){
				dis._animDic[key] = _animDic[key];
			}
			
			dis._curentAction = _curentAction
			
			return dis;
		}
		
	}
}